﻿using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;

namespace Idte.Core.Infrastructure.Repository
{
    public class RepositoryBase<TEntity> : IRepository<TEntity> where TEntity : class, new()
    {
        protected readonly DbSet<TEntity> dbSet;

        protected DbContext DbContext { get; set; }
        public RepositoryBase(DbContext dbContext)
        {
            this.DbContext = dbContext;
            dbSet = dbContext.Set<TEntity>();
        }

        public virtual IQueryable<TEntity> Get(Expression<Func<TEntity, bool>> predicate)
        { 
            return this.DbContext.Set<TEntity>().Where(predicate);
        }

        public virtual IQueryable<TEntity> GetAll()
        {
            return this.DbContext.Set<TEntity>();
        }

        public virtual void Insert(TEntity entity)
        {
            DbEntityEntry<TEntity> entityEntry = this.DbContext.Entry(entity);
            if ((entityEntry.State != EntityState.Detached))
            {
                entityEntry.State = EntityState.Added;
                
            }
            else
            {
               // dbSet.Attach(entity);
                dbSet.Add(entity);
            }
        }

        public virtual TEntity Update(TEntity entity, Expression<Func<TEntity, bool>> predicate)
        {
            DbEntityEntry<TEntity> entityEntry = this.DbContext.Entry(entity);
            TEntity t;

            if (entity is IObjectWithChangeTracker)
            {
                IObjectWithChangeTracker trackedEntity = (IObjectWithChangeTracker)entity;

                foreach (EntityState state in Enum.GetValues(typeof(EntityState)))
                {
                    if (trackedEntity.ChangeTracker.ChangedStateCollection.ContainsKey(state))
                    {
                        foreach (var change in trackedEntity.ChangeTracker.ChangedStateCollection[state])
                        {
                            DbEntityEntry e = this.DbContext.Entry(change);
                            e.State = state;
                        }
                    }
                }
            }

            if (entityEntry.State == EntityState.Detached)
            {
                t = dbSet.Where(predicate).FirstOrDefault();
                entityEntry = this.DbContext.Entry(t);
                entityEntry.CurrentValues.SetValues(entity);
            }
            else
            {
                t = entity;
            }
            
            
            entityEntry.State = EntityState.Modified;
            return t;
        }

        public virtual void Delete(TEntity entity)
        {
            DbEntityEntry<TEntity> entityEntry = this.DbContext.Entry(entity);
            if ((entityEntry.State != EntityState.Deleted))
            {
                entityEntry.State = EntityState.Deleted;
            }
            else
            {
                dbSet.Attach(entity);
                dbSet.Remove(entity);
            }
        }

        public virtual void Submit()
        {
            this.DbContext.SaveChanges();
        }
    }


}
